/**
 * FFMpeg解复用过程:
 *  1.初始化网络模块 avformat_network_init()
 *  2.打开封装格式上下文 avformat_open_input(ppFormatCtx, url, nullptr, nullptr)
 *  3.查看流信息 avformat_find_stream_info(pFormatCtx, nullptr)
 *  4.根据流信息 创建编码器 Codec_CreateDecode()
 *  5.初始化AVPacket av_packet_alloc()
 *以上是初始化解复用过程
 *  6.读取数据包(AVPacket) av_read_frame(pFormatCtx, pPacket)
 *  7.送入解码器解码 Codec_StartDecode
 *以上是解码过程
 *  8.停止解码器 Codec_DestroyDecode()
 *  9.关闭封装格式上下文 avformat_close_input(ppFormatCtx)
 *以上是释放封装格式上下文
 *
 */

#include "FFMpegCapture.h"

#define LOG_TAG "FFMpegCapture"

FFMpegCapture::FFMpegCapture(IPCameraDevice *pCapDev) : ICapture(pCapDev) {
  avformat_network_init();
  int32_t ret = openInput(&_pFormatCtx, pCapDev);
  if (ret < SUCCESS) {
    LOG_ERROR("openInput error. errCode:%d, errStr:%s", ret, av_err2str(ret))
    return;
  }

  ret = avformat_find_stream_info(_pFormatCtx, nullptr);
  if (ret < SUCCESS) {
    LOG_ERROR("avformat_find_stream_info error. errCode:%d, errStr:%s", ret, av_err2str(ret))
    return;
  }

  for (int i = 0; i < _pFormatCtx->nb_streams; ++i) {
    auto pCodecParam = _pFormatCtx->streams[i]->codecpar;
    if (pCodecParam->codec_id == AV_CODEC_ID_H264) {
      _VParam.pStream = _pFormatCtx->streams[i];
      if (pCapDev->isSoftDecode) {
        _pVDecoder = Codec_CreateDecoder(CodecType_X264, _VParam, this);
      } else {
        _pVDecoder = Codec_CreateDecoder(CodecType_H264MediaCodec, _VParam, this);
      }
    } else if (pCodecParam->codec_id == AV_CODEC_ID_AAC) {
      _AParam.pStream = _pFormatCtx->streams[i];
      _pADecoder = Codec_CreateDecoder(CodecType_AAC, _AParam, this);
    }
  }

  _pPacket = av_packet_alloc();
  pCapDev->devState = DeviceState_Init;
}

FFMpegCapture::~FFMpegCapture() noexcept {
  if (_pPacket) {
    av_packet_free(&_pPacket);
    _pPacket = nullptr;
  }

  Codec_DestroyDecoder(&_pVDecoder);
  Codec_DestroyDecoder(&_pADecoder);

  closeInput(&_pFormatCtx);

  avformat_network_deinit();
  _pDevice->devState = DeviceState_None;
}

void FFMpegCapture::startCapture() {
  if (_pDevice->devState == DeviceState_None)
    return;

  _pDevice->devState = DeviceState_Start;
  while (av_read_frame(_pFormatCtx, _pPacket) == SUCCESS) {
    if (_pDevice->devState != DeviceState_Start) {
      if (_pPacket->stream_index == _VParam.pStream->index) {
        if (!Codec_StartDecode(_pVDecoder, _pPacket)) {
          LOG_ERROR("Codec_StartDecode error. pVDecoder")
        }
      } else if (_pPacket->stream_index == _AParam.pStream->index) {
        if (!Codec_StartDecode(_pADecoder, _pPacket)) {
          LOG_ERROR("Codec_StartDecode error. pADecoder")
        }
      }
    }
    av_packet_unref(_pPacket);
  }
}

void FFMpegCapture::stopCapture() {
  if (_pDevice->devState == DeviceState_None)
    return;

  _pDevice->devState = DeviceState_Stop;
}

int32_t FFMpegCapture::capacity() {
  int32_t capacity = 0;
  if (_pVDecoder)
    capacity |= MediaType_Video;

  if (_pADecoder)
    capacity |= MediaType_Audio;

  return capacity;
}

void FFMpegCapture::onDecodeData(IDecoder *pDecoder, AVFrame *pFrame) {
  if (_pFrameCallback) {
    MediaFrame *pMediaFrame = nullptr;
    if (pDecoder->getMediaType() == MediaType_Video) {

    } else if (pDecoder->getMediaType() == MediaType_Audio) {

    }

    _pFrameCallback->onFrameCallback(this, pMediaFrame);
  }
}

